package com.xyazm.fulfill.event;

import com.xyazm.common.constants.RocketMqConstant;
import com.xyazm.common.enums.OrderStatusChangeEnum;
import com.xyazm.common.enums.OrderTypeEnum;
import com.xyazm.common.mq.MQMessage;
import com.xyazm.fulfill.dao.OrderFulfillDAO;
import com.xyazm.fulfill.dao.OrderFulfillLogDAO;
import com.xyazm.fulfill.domain.entity.OrderFulfillDO;
import com.xyazm.fulfill.domain.entity.OrderFulfillLogDO;
import com.xyazm.fulfill.domain.event.OrderEvent;
import com.xyazm.fulfill.domain.param.TriggerOrderAfterFulfillEventParam;
import com.xyazm.fulfill.enums.OrderFulfillOperateTypeEnum;
import com.xyazm.fulfill.mq.producer.DefaultProducer;
import com.xyazm.fulfill.utils.OrderFulfillOperateLogUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.springframework.beans.factory.annotation.Autowired;

import java.nio.charset.StandardCharsets;

/**
 * 订单履约后置事件 基类
 * @author xuyou
 * @date 2023年02月13日 20:35
 */
@Slf4j
public abstract class AbstractAfterFulfillEventProcessor implements OrderAfterFulfillEventProcessor {


    @Autowired
    private DefaultProducer defaultProducer;
    @Autowired
    protected OrderFulfillDAO orderFulfillDAO;
    @Autowired
    protected OrderFulfillLogDAO orderFulfillLogDAO;

    @Override
    public void execute(TriggerOrderAfterFulfillEventParam param, OrderFulfillDO orderFulfillDO) {
        // 判断是否是履约状态
        if (!checkFulfillStatus(orderFulfillDO)) {
            return;
        }
        // 执行业务逻辑
        doBizProcess(param, orderFulfillDO);
        // 判断是否需要发送订单履约后消息
        if (orderNeedSendMsg(param)) {
            // 构建消息体
            String body = buildMsgBody(param);
            // 发送消息
            sendMessage(body,param.getOrderId());
        }
    }


    /**
     * 判断是否是履约状态
     * @author xuyou
     * 2023-02-13 20:37
    */
    protected abstract boolean checkFulfillStatus(OrderFulfillDO orderFulfillDO);

    /**
     * 执行业务流程
     * @author xuyou
     * 2023-02-13 20:42
    */
    protected abstract void doBizProcess(TriggerOrderAfterFulfillEventParam param, OrderFulfillDO orderFulfill);

    /**
     * 判断是否需要发送订单履约后消息
     * @author xuyou
     * 2023-02-13 20:44
    */
    protected abstract boolean orderNeedSendMsg(TriggerOrderAfterFulfillEventParam param);

    /**
     * 构建消息体
     * @author xuyou
     * 2023-02-13 20:45
    */
    protected abstract String buildMsgBody(TriggerOrderAfterFulfillEventParam param);


    /**
     * 更新履约单状态 并且创建操作日志
     * @author xuyou
     * 2023-02-13 21:26
     * @param orderFulfillDO
     * @param operateType
    */
    protected void updateStatusAndSaveLog(OrderFulfillDO orderFulfillDO, OrderFulfillOperateTypeEnum operateType) {
        orderFulfillDAO.updateStatus(orderFulfillDO.getFulfillId(), operateType.getFromStatus().getCode(), operateType.getToStatus().getCode());
        // 创建履约单操作日志
        OrderFulfillLogDO orderFulfillLogDO = OrderFulfillOperateLogUtil.build(orderFulfillDO, operateType);
        orderFulfillLogDAO.save(orderFulfillLogDO);
    }

    protected <T> OrderEvent<T> buildOrderEvent(String orderId, OrderStatusChangeEnum orderStatusChangeEnum, T event) {
        OrderEvent<T> orderEvent = new OrderEvent<>();
        orderEvent.setOrderId(orderId);
        orderEvent.setBusinessIdentifier(1);
        orderEvent.setOrderType(OrderTypeEnum.NORMAL.getCode());
        orderEvent.setOrderStatusChange(orderStatusChangeEnum);
        orderEvent.setMessageContent(event);
        return orderEvent;
    }

    /**
     * 发送履约后消息
     * @author xuyou
     * 2023-02-13 20:46
    */
    private void sendMessage(String body, String orderId) {
        if (StringUtils.isNotEmpty(body)) {
            Message message = new MQMessage();
            message.setBody(body.getBytes(StandardCharsets.UTF_8));
            message.setTopic(RocketMqConstant.ORDER_WMS_SHIP_RESULT_TOPIC);
            try {
                DefaultMQProducer defaultMQProducer = defaultProducer.getProducer();
                SendResult sendResult = defaultMQProducer.send(message, (mqs, msg, arg) -> {
                    String orderId1 = (String) arg;
                    int index = hash(orderId1) % mqs.size();
                    return mqs.get(index);
                }, orderId);
                log.info("发送订单履约后置消息,SendResult status:{}, queueId:{}, body:{}", sendResult.getSendStatus(),
                        sendResult.getMessageQueue().getQueueId(), body);
            } catch (Exception e) {
                log.error("发送订单履约后置消息异常,orderId={},errMsg={}", orderId, e.getMessage());
            }
        }
    }


    private int hash(String orderId) {
        //解决取模可能为负数的情况
        return orderId.hashCode() & Integer.MAX_VALUE;
    }
}
